<!--
 * @description 组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<form class="pure-form" :class="_classes" :style="_styles">
		<slot></slot>
	</form>
</template>

<script>
import commonComponentOptions from "../../config/common-component-options";
import { isFunction } from "../../functions";
export default {
	options: commonComponentOptions,
};
</script>

<script setup>
import { ref, computed, provide, onMounted, defineExpose } from "vue";
import props from "./props";
import Schema from "async-validator";
import { isString, isArray, isPlainObject } from "../../functions";

// **************************************************************************************************************
// * Refs
// **************************************************************************************************************
// 字段单独设置的验证规则
const _filedsRules = ref({});

// 未验证通过的字段
const _invalidFields = ref({});

// **************************************************************************************************************
// * Options
// **************************************************************************************************************
defineOptions(commonComponentOptions);

// **************************************************************************************************************
// * Props
// **************************************************************************************************************
const _props = defineProps(props);

// **************************************************************************************************************
// * Emits
// **************************************************************************************************************
const _emits = defineEmits([]);

// **************************************************************************************************************
// * Classes
// **************************************************************************************************************
const _classes = computed(() => {
	const array = [];
	return array;
});

// **************************************************************************************************************
// * Styles
// **************************************************************************************************************
const _styles = computed(() => {
	const array = [];

	// 标签宽度
	if (_props.labelWidth)
		array.push(`--pure-form-item-left-width: ${_props.labelWidth}`);

	return array;
});

// **************************************************************************************************************
// * Computed
// **************************************************************************************************************
// 最终的表单验证规则 = 全局规则 + 字段单独设置的规则
const _finalRules = computed(() => {
	return {
		..._props.rules,
		..._filedsRules.value,
	};
});

// **************************************************************************************************************
// * 生命周期
// **************************************************************************************************************
onMounted(() => {
	// 将最终的验证规则先设置为全局规则
	// _finalRules.value = _props.rules;
});

// **************************************************************************************************************
// * Functions
// **************************************************************************************************************
// 更新字段的验证规则
function updatePureFormRules(fieldName, rules) {
	if (fieldName && rules) {
		_filedsRules.value[fieldName] = rules;
	}
}

// 表单校验
function validate() {
	// 验证器
	const validator = new Schema(_finalRules.value);

	// options 验证选项
	const options = {
		first: false, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
		firstFields: true, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
		suppressWarning: true, // 是否禁止无效值的内部警告
	};

	// 验证表单数据
	return new Promise((resolve, reject) => {
		validator
			.validate(_props?.model || {}, options, (errors, fields) => {
				// 验证未通过
				if (errors) {
					showError(errors, fields);
					reject(false);
				}

				// 验证通过
				else {
					_invalidFields.value = {};
					resolve(true);
				}
			})
			.catch(() => {});
	});
}

// 单字段验证
function validateField(fieldName) {
	const schema = {};
	schema[fieldName] = _finalRules.value[fieldName];

	// 验证器
	const validator = new Schema(schema);

	// options 验证选项
	const options = {
		first: false, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
		firstFields: true, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
		suppressWarning: true, // 是否禁止无效值的内部警告
	};

	// 验证表单数据
	return new Promise((resolve, reject) => {
		validator
			.validate(_props?.model || {}, options, (errors, fields) => {
				// 验证未通过
				if (errors) {
					console.log("字段验证未通过", errors, fields);
					showError(errors, fields);
					reject(false);
				}

				// 验证通过
				else {
					try {
						delete _invalidFields.value[fieldName];
					} catch (error) {}
					resolve(true);
				}
			})
			.catch(() => {});
	});
}

// 多字段验证
function validateFields(fieldNames = []) {
	const schema = {};
	fieldNames.forEach((fieldName) => {
		schema[fieldName] = _finalRules.value[fieldName];
	});

	// 验证器
	const validator = new Schema(schema);

	// options 验证选项
	const options = {
		first: false, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
		firstFields: true, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
		suppressWarning: true, // 是否禁止无效值的内部警告
	};

	// 验证表单数据
	return new Promise((resolve, reject) => {
		validator
			.validate(_props?.model || {}, options, (errors, fields) => {
				// 验证未通过
				if (errors) {
					showError(errors, fields);
					reject(false);
				}

				// 验证通过
				else {
					try {
						fieldNames.forEach((fieldName) => {
							delete _invalidFields.value[fieldName];
						});
					} catch (error) {}
					resolve(true);
				}
			})
			.catch(() => {});
	});
}

// 提示错误
function showError(errors, fields) {
	// 不提示
	if (_props?.errorMode === "none") {
		_invalidFields.value = {};
		return;
	}

	_invalidFields.value = {
		..._invalidFields.value,
		...fields,
	};

	// message: 在下方提示
	if (_props?.errorMode === "message") {
		return;
	}

	// toast: 弹出提示
	if (_props?.errorMode === "toast") {
		// 只弹窗提示第一个错误
		let firstError = errors?.[0];

		// 弹窗提示
		if (firstError) {
			uni.showToast({
				title: firstError?.message || "验证未通过",
				icon: "none",
			});
		}

		return;
	}
}

// 重置
function reset() {
	for (const key in _props.model) {
		if (isPlainObject(_props.model[key])) {
			resetObject(_props.model[key]);
		} else {
			_props.model[key] = null;
		}
	}
	_invalidFields.value = {};
}

// 将对象属性值全部设置为null
function resetObject(obj) {
	// 遍历对象属性
	for (const key in obj) {
		// 设置属性值为null
		obj[key] = null;
	}
}

// **************************************************************************************************************
// * Provides
// **************************************************************************************************************
// 表单数据
provide(
	"PureFormModel",
	computed(() => _props.model)
);

// 表单最终的验证规则
provide(
	"PureFormRules",
	computed(() => _finalRules.value)
);

// 未验证通过的字段
provide(
	"PureFormInvalidFields",
	computed(() => _invalidFields.value)
);

// 标签位置
provide(
	"PureFormLabelPosition",
	computed(() => _props.labelPosition)
);

// 必填符号
provide(
	"PureFormRequiredSymbol",
	computed(() => _props.requiredSymbol)
);

// 错误提示模式
provide(
	"PureFormErrorMode",
	computed(() => _props.errorMode)
);

// 更新字段的验证规则
provide("PureFormUpdatePureFormRules", updatePureFormRules);

// 单字段验证
provide("PureFormValidateField", validateField);

// **************************************************************************************************************
// * Expose
// **************************************************************************************************************
defineExpose({
	validate,
	validateField,
	validateFields,
	reset,
});
</script>

<style scoped lang="scss">
@import "./style.scss";
</style>
